﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.VisualBasic;

namespace Extension {
  /// <summary>
  /// string 类型的扩展方法
  /// </summary>
  public static class StringExt {
    /// <summary>
    /// 从此实例检索子字符串。子字符串从指定的字符位置开始且具有指定长度，可以使用负数
    /// </summary>
    /// <param name="str">字符串</param>
    /// <param name="startIndex">开始索引</param>
    /// <param name="length">长度</param>
    /// <returns></returns>
    public static string SubstringUsingNegtive(this string str, int startIndex, int length) {
      if(string.IsNullOrEmpty(str) || string.IsNullOrWhiteSpace(str)) return str;
      if(length < 0) throw new ArgumentException();

      if(startIndex >= 0) return str.Substring(startIndex, length);

      // 开始索引为负数
      var count = str.Length;
      var l = count - Math.Abs(startIndex);
      if(l < 0) throw new ArgumentOutOfRangeException($"Argument value: {startIndex} too small");

      var index = Math.Abs(startIndex) - length;
      if(index < 0) {
        var v = $"Argument value: {startIndex} too small Or {length} too big.";
        throw new ArgumentOutOfRangeException(v);
      }

      return str.Substring(count + startIndex, length);
      //var s = string.Join("", str.Reverse()).Substring(startIndex, length);
      //return string.Join("", s.Reverse());
    }

    /// <summary>
    /// 从此实例检索子字符串。子字符串从指定的字符位置开始且具有指定长度，可以使用负数
    /// </summary>
    /// <param name="str">字符串</param>
    /// <param name="startIndex">开始索引</param>
    /// <returns></returns>
    public static string SubstringUsingNegtive(this string str, int startIndex) {
      if(startIndex >= 0) return str.Substring(startIndex);

      var index = str.Length + startIndex;
      if(index < 0) throw new ArgumentOutOfRangeException($"Argument value: {startIndex} too small.");

      return str.Substring(index);
      //var length = Math.Abs(startIndex);

      //var s = string.Join("", str.Reverse()).Substring(0, length);
      //return string.Join("", s.Reverse());
    }
    /// <summary>
    /// 串联字符串数组的所有元素，其中在每个元素之间使用特定的分隔符。
    /// </summary>
    /// <param name="seperator">分隔符</param>
    /// <param name="values">字符串数组</param>
    /// <returns></returns>
    public static string Join(this string seperator, params string[] values) {
      return string.Join(seperator, values);
    }

    /// <summary>
    /// 将字符串数字转为大写形式
    /// </summary>
    /// <param name="str">数字字符串</param>
    /// <param name="style">大写的形式</param>
    /// <returns>转换后的字符串</returns>
    public static string ToUpperForChinese(this string str, UpperStyle style = UpperStyle.Upper) {
      var pattern = @"^(0|[1-9]\d*)(\.\d+)?$";
      Regex regex = new Regex(pattern);
      if(!regex.IsMatch(str)) throw new ArgumentException("不是数字。");

      var unit = "万仟佰拾亿仟佰拾万仟佰拾元角分";
      string result = string.Empty;
      string uppperNumber = "零壹贰叁肆伍陆柒捌玖";
      if(style == UpperStyle.Middle) {
        unit = "万千百十亿千百十万千百十元角分";
        uppperNumber = "〇一二三四五六七八九";
      }

      str += "00";

      var indexPoint = str.IndexOf(".", StringComparison.Ordinal);
      if(indexPoint >= 0) {
        str = str.Substring(0, indexPoint) + str.Substring(indexPoint + 1, 2);
      }

      // 截取需要使用的单位
      var count = unit.Length - str.Length;
      if(count < 0) throw new ArgumentException("数字太大，最大 13 位数字");

      unit = unit.Substring(count);
      var length = str.Length;
      for(int i = 0; i < length; i++) {
        var index = str.CharAt(i);
        result += uppperNumber[index] + unit[i].ToString();
      }
      if(style == UpperStyle.Middle) {
        result = Replace(result, "〇(千|百|十|角|分)", "〇");
        result = Replace(result, "〇+", "〇");
        result = Regex.Replace(result, "〇[亿万元]", m => m.Value[1].ToString());
        result = Replace(result, "亿万", "亿");
        result = Replace(result, "〇$", "");
        result = Replace(result, "元$", "元整");

        return result;
      }
      // 替换掉数字里面的 零 字符，得到结果
      result = Replace(result, "零(仟|佰|拾|角|分)", "零");
      result = Replace(result, "零+", "零");
      result = Regex.Replace(result, "零[亿万元]", m => m.Value[1].ToString());
      //s = Replace(s, "零元", "元");
      //s = Replace(s, "零万", "万");
      //s = Replace(s, "零亿", "亿");
      result = Replace(result, "亿万", "亿");
      result = Replace(result, "零$", "");
      result = Replace(result, "元$", "元整");

      return result;
    }

    /// <summary>
    /// 返回指定位置的字符，并将其转换为整数
    /// </summary>
    /// <param name="number">目标字符串</param>
    /// <param name="i">索引</param>
    /// <returns></returns>
    public static int CharAt(this string number, int i) {
      int.TryParse(number[i].ToString(), out int result);
      return result;
    }

    /// <summary>
    /// 使用正则表达式替换字符串中的子字符串
    /// </summary>
    /// <param name="str">目标字符串</param>
    /// <param name="pattern">正则表达式</param>
    /// <param name="replaceStr">替换的字符串</param>
    /// <param name="options">正则表达式选项</param>
    /// <returns>替换后的字符串</returns>
    public static string Replace(this string str, string pattern, string replaceStr, RegexOptions options = RegexOptions.None) {
      return Regex.Replace(str, pattern, replaceStr, options);
    }
    /// <summary>
    /// 在指定的字符串内，使用MatchEvaluator委托返回的字符串替换正则表达式匹配的字符串
    /// </summary>
    /// <param name="str">字符串</param>
    /// <param name="pattern">正则表达式</param>
    /// <param name="evaluator">委托返回的字符串替换匹配正则表达式的字符串</param>
    /// <returns>替换后的字符串</returns>
    public static string Replace(this string str, string pattern, MatchEvaluator evaluator) {
      return Regex.Replace(str, pattern, evaluator);
    }

    /// <summary>
    /// 将字符串转换为 int 类型
    /// </summary>
    /// <param name="str">需要转换的字符串</param>
    /// <param name="defaultValue">默认值</param>
    /// <returns></returns>
    public static int ToInt(this string str, int? defaultValue = null) {
      int result;
      try {
        result = (int)ToDouble(str);
      } catch(Exception) {
        // 如果没有值，则重新抛出异常
        if(!defaultValue.HasValue) throw;

        result = defaultValue.Value;
      }
      return result;
    }

    /// <summary>
    /// 将字符串转换为 double 类型
    /// </summary>
    /// <param name="str">要转换的字符串</param>
    /// <param name="defaultValue">默认值，当转换失败时，使用默认值</param>
    /// <returns></returns>
    public static double ToDouble(this string str, double? defaultValue = null) {
      if(string.IsNullOrEmpty(str)) {
        return defaultValue ?? throw new ArgumentNullException();
      }

      var pattern = @"^\d+|\d+\.\d+|[-+]\d+|[-+]\d+\.\d+$";
      var regex = new Regex(pattern);
      if(!regex.IsMatch(str)) {
        if(defaultValue.HasValue) return defaultValue.Value;

        throw new ArgumentException("Argument is not a number.");
      }

      double.TryParse(str, out double result);
      return result;
    }

    /// <summary>
    /// 转全角(full-width character)
    /// </summary>
    /// <param name="input">任意字符串</param>
    /// <returns>全角字符串</returns>
    public static string ToFullWidthCharacters(this string input) {
      char[] c = input.ToCharArray();
      for(int i = 0; i < c.Length; i++) {
        if(c[i] == 32) {
          c[i] = (char)12288;
          continue;
        }
        if(c[i] < 127) c[i] = (char)(c[i] + 65248);
      }
      return new string(c);
    }
    /// <summary>
    /// 转半角(half-width character)
    /// </summary>
    /// <param name="input">任意字符串</param>
    /// <returns>半角字符串</returns>
    public static string ToHalfWidthCharacters(this string input) {
      char[] c = input.ToCharArray();
      for(int i = 0; i < c.Length; i++) {
        if(c[i] == 12288) {
          c[i] = (char)32;
          continue;
        }
        if(c[i] > 65280 && c[i] < 65375) c[i] = (char)(c[i] - 65248);
      }
      return new string(c);
    }
    // 汉字对拼音字典
    private static readonly Dictionary<int, string> CodeCollections = new Dictionary<int, string> {
      { -20319, "a" },{ -20317, "ai" },{ -20304, "an" },{ -20295, "ang" },{ -20292, "ao" },
      { -20283, "ba" },{ -20265, "bai" },{ -20257, "ban" }, { -20242, "bang" },
      { -20230, "bao" }, { -20051, "bei" }, { -20036, "ben" }, { -20032, "beng" },
      { -20026, "bi" }, { -20002, "bian" }, { -19990, "biao" }, { -19986, "bie" },
      { -19982, "bin" }, { -19976, "bing" }, { -19805, "bo" },{ -19784, "bu" },
      { -19775, "ca" }, { -19774, "cai" }, { -19763, "can" }, { -19756, "cang" },
      { -19751, "cao" }, { -19746, "ce" },{ -19741, "ceng" }, { -19739, "cha" },
      { -19728, "chai" }, { -19725, "chan" }, { -19715, "chang" }, { -19540, "chao" },
      { -19531, "che" }, { -19525, "chen" }, { -19515, "cheng" }, { -19500, "chi" },
      { -19484, "chong" }, { -19479, "chou" },{ -19467, "chu" }, { -19289, "chuai" },
      { -19288, "chuan" }, { -19281, "chuang" }, { -19275, "chui" }, { -19270, "chun" },
      { -19263, "chuo" }, { -19261, "ci" }, { -19249, "cong" }, { -19243, "cou" },
      { -19242, "cu" }, { -19238, "cuan" },{ -19235, "cui" }, { -19227, "cun" },
      { -19224, "cuo" }, { -19218, "da" }, { -19212, "dai" }, { -19038, "dan" },
      { -19023, "dang" },{ -19018, "dao" }, { -19006, "de" }, { -19003, "deng" },
      { -18996, "di" },
      { -18977, "dian" }, { -18961, "diao" }, { -18952, "die" }, { -18783, "ding" },
      { -18774, "diu" }, { -18773, "dong" }, { -18763, "dou" }, { -18756, "du" },
      { -18741, "duan" },{ -18735, "dui" }, { -18731, "dun" }, { -18722, "duo" },
      { -18710, "e" }, { -18697, "en" }, { -18696, "er" }, { -18526, "fa" },
      { -18518, "fan" }, { -18501, "fang" }, { -18490, "fei" }, { -18478, "fen" },
      { -18463, "feng" }, { -18448, "fo" }, { -18447, "fou" }, { -18446, "fu" },
      { -18239, "ga" }, { -18237, "gai" }, { -18231, "gan" }, { -18220, "gang" },
      { -18211, "gao" }, { -18201, "ge" },{ -18184, "gei" }, { -18183, "gen" },
      { -18181, "geng" }, { -18012, "gong" }, { -17997, "gou" }, { -17988, "gu" },
      { -17970, "gua" }, { -17964, "guai" }, { -17961, "guan" }, { -17950, "guang" },
      { -17947, "gui" }, { -17931, "gun" }, { -17928, "guo" },{ -17922, "ha" },
      { -17759, "hai" }, { -17752, "han" }, { -17733, "hang" }, { -17730, "hao" },
      { -17721, "he" }, { -17703, "hei" },{ -17701, "hen" }, { -17697, "heng" },
      { -17692, "hong" }, { -17683, "hou" }, { -17676, "hu" }, { -17496, "hua" },
      { -17487, "huai" }, { -17482, "huan" }, { -17468, "huang" },
      { -17454, "hui" }, { -17433, "hun" }, { -17427, "huo" },{ -17417, "ji" },
      { -17202, "jia" }, { -17185, "jian" }, { -16983, "jiang" }, { -16970, "jiao" },
      { -16942, "jie" },{ -16915, "jin" }, { -16733, "jing" }, { -16708, "jiong" },
      { -16706, "jiu" }, { -16689, "ju" }, { -16664, "juan" },{ -16657, "jue" },
      { -16647, "jun" }, { -16474, "ka" }, { -16470, "kai" }, { -16465, "kan" },
      { -16459, "kang" }, { -16452, "kao" },{ -16448, "ke" }, { -16433, "ken" },
      { -16429, "keng" }, { -16427, "kong" }, { -16423, "kou" }, { -16419, "ku" },
      { -16412, "kua" }, { -16407, "kuai" }, { -16403, "kuan" }, { -16401, "kuang" },
      { -16393, "kui" }, { -16220, "kun" }, { -16216, "kuo" },{ -16212, "la" },
      { -16205, "lai" }, { -16202, "lan" }, { -16187, "lang" }, { -16180, "lao" },
      { -16171, "le" }, { -16169, "lei" },{ -16158, "leng" }, { -16155, "li" },
      { -15959, "lia" }, { -15958, "lian" }, { -15944, "liang" }, { -15933, "liao" },
      { -15920, "lie" }, { -15915, "lin" }, { -15903, "ling" },
      { -15889, "liu" }, { -15878, "long" }, { -15707, "lou" }, { -15701, "lu" },
      { -15681, "lv" }, { -15667, "luan" }, { -15661, "lue" }, { -15659, "lun" },
      { -15652, "luo" }, { -15640, "ma" }, { -15631, "mai" },
      { -15625, "man" }, { -15454, "mang" }, { -15448, "mao" }, { -15436, "me" },
      { -15435, "mei" }, { -15419, "men" },{ -15416, "meng" }, { -15408, "mi" },
      { -15394, "mian" }, { -15385, "miao" },{ -15377, "mie" }, { -15375, "min" },
      { -15369, "ming" }, { -15363, "miu" }, { -15362, "mo" }, { -15183, "mou" },
      { -15180, "mu" }, { -15165, "na" }, { -15158, "nai" },{ -15153, "nan" },
      { -15150, "nang" }, { -15149, "nao" }, { -15144, "ne" }, { -15143, "nei" },
      { -15141, "nen" }, { -15140, "neng" }, { -15139, "ni" }, { -15128, "nian" },
      { -15121, "niang" }, { -15119, "niao" }, { -15117, "nie" }, { -15110, "nin" },
      { -15109, "ning" }, { -14941, "niu" }, { -14937, "nong" }, { -14933, "nu" },
      { -14930, "nv" }, { -14929, "nuan" }, { -14928, "nue" }, { -14926, "nuo" },
      { -14922, "o" }, { -14921, "ou" }, { -14914, "pa" },
      { -14908, "pai" }, { -14902, "pan" }, { -14894, "pang" },
      { -14889, "pao" }, { -14882, "pei" }, { -14873, "pen" }, { -14871, "peng" },
      { -14857, "pi" }, { -14678, "pian" },
      { -14674, "piao" }, { -14670, "pie" }, { -14668, "pin" }, { -14663, "ping" },
      { -14654, "po" }, { -14645, "pu" }, { -14630, "qi" },
      { -14594, "qia" }, { -14429, "qian" }, { -14407, "qiang" }, { -14399, "qiao" },
      { -14384, "qie" }, { -14379, "qin" },
      { -14368, "qing" }, { -14355, "qiong" }, { -14353, "qiu" }, { -14345, "qu" },
      { -14170, "quan" }, { -14159, "que" },
      { -14151, "qun" }, { -14149, "ran" }, { -14145, "rang" }, { -14140, "rao" },
      { -14137, "re" }, { -14135, "ren" }, { -14125, "reng" }, { -14123, "ri" },
      { -14122, "rong" }, { -14112, "rou" }, { -14109, "ru" },
      { -14099, "ruan" }, { -14097, "rui" }, { -14094, "run" }, { -14092, "ruo" },
      { -14090, "sa" }, { -14087, "sai" }, { -14083, "san" },
      { -13917, "sang" }, { -13914, "sao" }, { -13910, "se" }, { -13907, "sen" },
      { -13906, "seng" }, { -13905, "sha" }, { -13896, "shai" },
      { -13894, "shan" }, { -13878, "shang" },
      { -13870, "shao" }, { -13859, "she" }, { -13847, "shen" }, { -13831, "sheng" },
      { -13658, "shi" }, { -13611, "shou" },
      { -13601, "shu" }, { -13406, "shua" }, { -13404, "shuai" }, { -13400, "shuan" },
      { -13398, "shuang" }, { -13395, "shui" },
      { -13391, "shun" }, { -13387, "shuo" }, { -13383, "si" }, { -13367, "song" },
      { -13359, "sou" }, { -13356, "su" },
      { -13343, "suan" }, { -13340, "sui" }, { -13329, "sun" }, { -13326, "suo" },
      { -13318, "ta" }, { -13147, "tai" }, { -13138, "tan" },
      { -13120, "tang" }, { -13107, "tao" }, { -13096, "te" }, { -13095, "teng" },
      { -13091, "ti" }, { -13076, "tian" },
      { -13068, "tiao" }, { -13063, "tie" }, { -13060, "ting" }, { -12888, "tong" },
      { -12875, "tou" }, { -12871, "tu" },
      { -12860, "tuan" }, { -12858, "tui" }, { -12852, "tun" }, { -12849, "tuo" },
      { -12838, "wa" }, { -12831, "wai" }, { -12829, "wan" }, { -12812, "wang" },
      { -12802, "wei" }, { -12607, "wen" }, { -12597, "weng" },
      { -12594, "wo" }, { -12585, "wu" }, { -12556, "xi" }, { -12359, "xia" },
      { -12346, "xian" }, { -12320, "xiang" }, { -12300, "xiao" },
      { -12120, "xie" }, { -12099, "xin" },
      { -12089, "xing" }, { -12074, "xiong" }, { -12067, "xiu" }, { -12058, "xu" },
      { -12039, "xuan" }, { -11867, "xue" },
      { -11861, "xun" }, { -11847, "ya" }, { -11831, "yan" }, { -11798, "yang" },
      { -11781, "yao" }, { -11604, "ye" }, { -11589, "yi" },
      { -11536, "yin" }, { -11358, "ying" }, { -11340, "yo" }, { -11339, "yong" },
      { -11324, "you" }, { -11303, "yu" },
      { -11097, "yuan" }, { -11077, "yue" }, { -11067, "yun" }, { -11055, "za" },
      { -11052, "zai" }, { -11045, "zan" },
      { -11041, "zang" }, { -11038, "zao" }, { -11024, "ze" }, { -11020, "zei" },
      { -11019, "zen" }, { -11018, "zeng" },
      { -11014, "zha" }, { -10838, "zhai" }, { -10832, "zhan" }, { -10815, "zhang" },
      { -10800, "zhao" }, { -10790, "zhe" },
      { -10780, "zhen" }, { -10764, "zheng" }, { -10587, "zhi" }, { -10544, "zhong" },
      { -10533, "zhou" }, { -10519, "zhu" },
      { -10331, "zhua" }, { -10329, "zhuai" }, { -10328, "zhuan" }, { -10322, "zhuang" },
      { -10315, "zhui" }, { -10309, "zhun" },
      { -10307, "zhuo" }, { -10296, "zi" }, { -10281, "zong" }, { -10274, "zou" },
      { -10270, "zu" }, { -10262, "zuan" }, { -10260, "zui" }, { -10256, "zun" },
      { -10254, "zuo" } };

    /// <summary>
    /// 获取汉字拼音首字母(未测试)
    /// </summary>
    /// <returns>汉字拼音首字母，其它字符原样返回</returns>
    public static string GetChineseSpell(this string str) {
      // copy 网络上的代码
      str = str.Trim();
      //每个汉字为2字节 
      //使用StringBuilder优化字符串连接 
      StringBuilder result = new StringBuilder();
      char[] arrChar = str.ToCharArray();
      //遍历输入的字符 
      foreach(char t in arrChar) {
        //根据系统默认编码得到字节码 
        byte[] arr = Encoding.Default.GetBytes(t.ToString());
        //如果只有1字节说明该字符不是汉字，结束本次循环 
        if(arr.Length == 1) {
          result.Append(t.ToString());
          continue;
        }
        int arr1 = arr[0];
        int arr2 = arr[1];
        //计算汉字的编码 
        var charCode = arr1 * 256 + arr2 - 65536;
        //如果不在汉字编码范围内则不改变
        if(charCode > -10254 || charCode < -20319) {
          result.Append(t);
        } else {
          //根据汉字编码范围查找对应的拼音并保存到结果中 
          //由于charCode的键不一定存在，所以要找比他更小的键上一个键 
          if(!CodeCollections.ContainsKey(charCode)) {
            for(int i = charCode; i <= 0; --i) {
              if(CodeCollections.ContainsKey(i)) {
                result.Append($" {CodeCollections[i]} ");
                break;
              }
            }
          } else {
            result.Append($" {CodeCollections[charCode]} ");
          }
        }
      }
      return result.ToString();
    }

    /// <summary>
    /// 转繁体中文
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static string ToTraditionalChinese(this string str) {
      if(string.IsNullOrEmpty(str)) return str;

      string v = str.Trim();
      // 使用微软提供的VB函数
      return Strings.StrConv(v, VbStrConv.TraditionalChinese);
    }
    /// <summary>
    /// 转简体中文
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static string ToSimpleChinese(this string str) {
      if(string.IsNullOrEmpty(str)) return str;

      string v = str.Trim();
      // 使用微软提供的VB函数
      return Strings.StrConv(v, VbStrConv.SimplifiedChinese);
    }

    /// <summary>
    /// 指示指定的字符串是 null 还是 string.Empty
    /// </summary>
    /// <param name="str">目标字符串</param>
    /// <returns></returns>
    public static bool IsNullOrEmpty(this string str) {
      return string.IsNullOrEmpty(str);
    }
    /// <summary>
    /// 指示指定的字符串是 null 还是 string.Empty 或者是仅由空白(\n\t\r\v等)组成的字符串
    /// </summary>
    /// <param name="str">目标字符串</param>
    /// <returns></returns>
    public static bool IsNullOrEmptyOrWhiteSpace(this string str) {
      return string.IsNullOrWhiteSpace(str) || string.IsNullOrEmpty(str);
    }

    // 扩展 Format
    public static string FormatWith(this string format, params object[] args) {
      return string.Format(format, args);
    }
    /// <summary>
    /// 计算字符串的 MD5 值。若字符串为空，则返回空，否则返回计算结果。
    /// </summary>
    /// <param name="str">目标字符串</param>
    /// <returns></returns>
    public static string ComputeMd5(this string str) {
      StringBuilder hash = new StringBuilder();
      if(IsNullOrEmptyOrWhiteSpace(str)) return str;

      MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
      byte[] data = Encoding.UTF8.GetBytes(str);
      byte[] datas = md5.ComputeHash(data);
      foreach(byte d in datas) {
        hash.Append(d.ToString("x"));
      }

      return hash.ToString();
    }

    /// <summary>
    /// 指示所指定的正则表达式在指定的字符串中是否找到了匹配项
    /// </summary>
    /// <param name="input">指定的字符串</param>
    /// <param name="pattern">正则表达式</param>
    /// <returns></returns>
    public static bool IsMatch(this string input, string pattern) {
      return input != null && Regex.IsMatch(input, pattern);
    }

    /// <summary>
    /// 在指定的字符串中搜索指定的正则表达式第一个匹配的项
    /// </summary>
    /// <param name="input">指定的字符串</param>
    /// <param name="pattern">正则表达式</param>
    /// <returns></returns>
    public static string Match(this string input, string pattern) {
      return input == null ? string.Empty : Regex.Match(input, pattern).Value;
    }

    /// <summary>
    /// 将字符串转为Camel命名法（首字母小写）
    /// </summary>
    /// <param name="str">目标字符串</param>
    /// <returns></returns>
    public static string ToCamel(this string str) {
      if(string.IsNullOrEmpty(str)) return str;
      return str[0].ToString().ToLower() + str.Substring(1);
    }
    /// <summary>
    /// 将字符串转为Pascal命名法（首字母大写）
    /// </summary>
    /// <param name="str">目标字符串</param>
    /// <returns></returns>
    public static string ToPascal(this string str) {
      if(string.IsNullOrEmpty(str)) return str;
      return str[0].ToString().ToUpper() + str.Substring(1);
    }
  }
}
